import JsCookies from 'js-cookie'
import Config from '@/api/config'

//请求对象
let targets = {
  kline:'kline',
  depth:'depth',
  deal:'deal',
  price:'price',
  today:'today',
  server:'server',
  fiatrate:'fiatrate',
  assets:'assets',
  order:'order',
  market:'market',
  step_price:'step_price'
}

//定义请求对象方法
let methods = {
  query:'query',
  sub:'sub',
  unsub:'unsub',
  ping:'ping',
  time:'time',
  auth:'auth'
}

//分配请求对象方法id值
let ids = {
  kline:{
    query:1,
    sub:2,
    unsub:3,
  },
  deal:{
    query:4,
    sub:5,
    unsub:6,
  },
  price:{
    query:7,
    sub:8,
    unsub:9,
  },
  today:{
    query:10,
    sub:11,
    unsub:12,
  },
  depth:{
    query:13,
    sub:14,
    unsub:15,
  },
  fiatrate:{
    query:16,
    sub:17,
    unsub:18,
  },
  assets:{
    sub:19,
    unsub:20,
  },
  order:{
    sub:21,
    unsub:22,
  },
  market:{
    sub:23,
    unsub:24,
  },
  server:{
    ping:25,
    time:26,
    auth:27
  },
  step_price:{
    query:28,
    sub:29,
    unsub:30,
  }
}

//转换订阅周期
function getPeriod(resolution) {
    if(isNaN(resolution)){
      switch (resolution) {
        case '1s':
          resolution = 1
          break
        case '1D':
          resolution = 60*60*24
          break
        case '1W':
          resolution = 60*60*24*7
          break
        case '1M':
          resolution = 60*60*24*30
          break
      }
    } else {
      resolution = resolution * 60
    }
    return resolution
}

//打印网络状态
function logState(level) {
  let _level = {
    '0':'优',
    '1':'中',
    '2':'弱',
  }
  console.log(`网络监测：${_level[level]}`)
}


export {targets, methods, ids, getPeriod, logState}


/*opts 
* @target 数据获取对象
* @method 数据获取方法 query、sub
* @params 对应的参数
* @symbol 订阅市场，默认ethusdt市场，可以为String、Array
* @period k线周期，默认30分钟K线，可以为String、Number； String语义化取值参考上面getPeriod函数，Number 以秒为单位
* @length 一次性K线加载条数，默认200条数据；当订阅主题为最新成交时，为加载数据条数，默认100条
* @digit 保留的小数位数，默认为8位
* @callback 订阅回调函数
*/
export default function () {
  let subscribeArray = {} //暂存订阅信息
  let timeSubs = [] //暂存需要服务器时间的订阅
  let authSubs = [] //暂存需要apiToken授权的订阅
  let initSubState = false //是否已进行初始化订阅
  let checkNetWorkCallback = null //网络监测函数
  let rateCallback = null //汇率监测函数
  let opts = {}
  let serverTime = null
  let hasAuth = false //是否已登录
  let target = null
  let method = null
  let params = []
  let id = null
  let timer = null

  let isLeavePage = false
  let webSocket = null
  
  function initParams(){ // 对params未传时，补充完整params参数
    if(!params.length && (method==methods.query || method==methods.sub)){
      if([targets.kline, targets.depth, targets.deal, targets.price, targets.today, targets.step_price].includes(target)){
        !opts.symbol?params.push('vtxusdt'):(opts.symbol.constructor.name=='Array'?params=opts.symbol:params.push(opts.symbol)) //默认拉取btcusdt市场
      }
      if(target==targets.kline){
        let _period = opts.period || '30' //默认显示30分钟K线
        _period = getPeriod(_period)
        if(method==methods.query){
          let _length = opts.length || 200 //默认加载200条K线
          if(opts.timestamp){
            params.push(opts.timestamp - _period * _length)
            params.push(opts.timestamp)
          } else {
            params.push(serverTime - _period * _length)
            params.push(serverTime)
          }
          params.push(_period)
        } else {
          params.push(_period)
        }
        
      } else if(target==targets.depth || (target==targets.deal && method==methods.query)){
        let _length = opts.length || 100 //默认加载100条最新成交数据
        params.push(_length)
        if(target==targets.depth){
          let _digit = opts.digit || 8 //默认保留8位小数
          params.push(_digit)
        }
      }
    }
  }

  function getNow (){ //获取服务器时间
    if (webSocket && webSocket.readyState === webSocket.OPEN) {
      let _target = targets.server, _method = methods.time
      let _params = {"method":`${_target}.${_method}`, "params":[], "id":ids[_target][_method]}
      webSocket.send(JSON.stringify(_params))
    }
  }

  function setAuth (){ //设置或清除socket的api_token状态
    let _apiToken = JsCookies.get('api_token') || ''
    if (webSocket && webSocket.readyState === webSocket.OPEN) {
      let _target = targets.server, _method = methods.auth
      let _params = {"method":`${_target}.${_method}`, "params":_apiToken?[_apiToken]:[], "id":ids[_target][_method]}
      webSocket.send(JSON.stringify(_params))
    }
  }

  function sendMessage () { //发送订阅消息
    if (webSocket && webSocket.readyState === webSocket.OPEN) {
      let _params = {"method":`${target}.${method}`, "params":params, "id":id}
      webSocket.send(JSON.stringify(_params))
    }
  }

  function getRate (){ //获取汇率及推送
    if (webSocket && webSocket.readyState === webSocket.OPEN) {
      let _target = targets.fiatrate, _method = methods.sub
      let _params = {"method":`${_target}.${_method}`, "params":[], "id":ids[_target][_method]}
      webSocket.send(JSON.stringify(_params))
    }
  }

  function checkNetWork () { //socket 心跳及网络测速
    if (webSocket && webSocket.readyState === webSocket.OPEN) {
      let _target = targets.server, _method = methods.ping
      let _now = new Date().getTime()
      let _params = {"method":`${_target}.${_method}`, "params":[_now], "id":ids[_target][_method]}
      webSocket.send(JSON.stringify(_params))
    }
  }

  function subscribe(_opts) { //订阅入口，存储订阅列表方便回调
    _opts = _opts || {}
    let _target = _opts.target || targets.server
    let _method = _opts.method || methods.ping
    let _id = ids[_target][_method]
    if(_method == methods.sub){
      _id = `${_target}.update`
    }

    subscribeArray[_id] = _opts
    if(!serverTime){ //需要服务器时间做订阅前提
      if([targets.kline].includes(_target)){
        timeSubs.push(_opts)
        return 
      }
    }

    if(!hasAuth){ //需要授权用户apiToken做订阅前提
      if([targets.assets, targets.order].includes(_target)){
        authSubs.push(_opts)
        return 
      }
    }
    if(initSubState){
      opts = _opts || {}
      target = _opts.target || targets.server
      method = _opts.method || methods.ping
      params = _opts.params || []
      id = ids[target][method]
      initParams()
      sendMessage()
    }
  }

  function startSubs(key) { //开启订阅
    let _subs
    if(!key){
      _subs =  Object.values(subscribeArray).filter(_opts=>{
        _opts = _opts || {}
        let _target = _opts.target || targets.server
        return [targets.assets, targets.order, targets.kline].includes(_target)?false:true
      })
    }
    _subs = key=='all'?Object.values(subscribeArray):(key=='auth'?authSubs:(key=='time'?timeSubs:_subs))
    // console.log(key,'_subs=',_subs)
    _subs.forEach(_opts=>{
      opts = _opts || {}
      target = _opts.target || targets.server
      method = _opts.method || methods.ping
      params = _opts.params || []
      id = ids[target][method]
      initParams()
      sendMessage()
    })
    initSubState = true
  }

  function unsubscribe(tars) { //取消对象的订阅
    return new Promise(resoveAll=>{
      if (webSocket && webSocket.readyState === webSocket.OPEN) {
        const promiseList = tars.split(',').map(tar=>{
          return new Promise(resove=>{
            let _target = targets[tar], _method = methods.unsub
            if(!_target){
              resove()
              return
            }
            let _id = ids[_target][_method]
            subscribeArray[_id] = {
              target:_target,
              method:_method,
              callback:(data)=>{
                delete subscribeArray[`${_target}.update`]
                resove()
              }
            }
            let _params = {"method":`${_target}.${_method}`, "params":[], "id":_id}
            webSocket.send(JSON.stringify(_params))
          })
        })
        Promise.all(promiseList).then(()=>{
          resoveAll()
        })
      } else {
        resoveAll()
      }
    })
  }

  function createWebSocket (key) { //创建websocket连接
    let ws = new WebSocket(`${Config.wshttp}${Config.domain}/ws`)
    // let ws = new WebSocket(`ws://10.0.5.97:9999/ws`)
    ws.onopen = function () {
      console.log(`open websocket`)
      getNow() //先获取服务器时间
      setAuth() //设置当前用户的apiToken
      getRate() //获取实时汇率
      startSubs(key) //开始初始化订阅
      checkNetWork() //创建心跳及网络监测
    }
    ws.onmessage = function (res) {
      try {
        res = JSON.parse(res.data)
        let _data = res.result || res.params
        if(!res.method){
          if (res.id == ids[targets.server][methods.auth]) {
            hasAuth = true
            startSubs('auth') //订阅授权数据
            return
          }
          if (res.id == ids[targets.server][methods.time]) {
            serverTime = Math.floor(res.result/1000)
            timer = setInterval(()=>{
              serverTime += 1
            },1000)
            startSubs('time') //订阅授时数据
            return
          }
          if (res.id == ids[targets.server][methods.ping]) { //心跳及健康检查
            let interval = new Date().getTime() - res.result
            // console.log(`网络延迟：${interval}毫秒`)
            let minMS = 200
            let maxMS = 400
            if (interval < minMS) {
              // 网络信号优
              checkNetWorkCallback && checkNetWorkCallback(0)
            } else if (interval >= minMS && interval < maxMS) {
              // 网络信号中
              checkNetWorkCallback && checkNetWorkCallback(1)
            } else if (interval >= maxMS) {
              // 网络信号弱
              checkNetWorkCallback && checkNetWorkCallback(2)
            }
            // 每隔3秒检测一下网络
            setTimeout(() => {
              if (this.readyState === this.OPEN) {
                checkNetWork()
              }
            }, 10000)
            return
          }
          subscribeArray[res.id] && subscribeArray[res.id]['callback'] && subscribeArray[res.id]['callback'](_data)
          delete subscribeArray[res.id]
        } else {
          if (res.method == 'fiatrate.update') { //汇率处理
            rateCallback && rateCallback(res.result || res.params)
            return
          }
          subscribeArray[res.method] && subscribeArray[res.method]['callback'] && subscribeArray[res.method]['callback'](_data)
        }
      } catch (ex) {
        console.warn(ex)
      }
    }
    ws.onclose = function () {
      console.log(`close websocket`)
      serverTime = null
      clearInterval(timer)
      timer = null
      typeof opts.onClose === 'function' && opts.onClose()
      setTimeout(function () {
        if (isLeavePage) {
          return
        }
        webSocket = createWebSocket()
      }, 3000)
    }
    ws.onerror = function () {
      console.log(`error websocket`)
    }
    return ws
  }
  webSocket = createWebSocket()

  return {
    close () {
      isLeavePage = true
      if (webSocket) {
        webSocket.close()
      }
    },
    changeLogin () {
      setAuth()
    },
    switchSymbol (symbol) {
      symbol = symbol.toLowerCase()
      for(let item of Object.values(subscribeArray)){
        if(typeof item.symbol=='string'){
          item.symbol = symbol
        }
      }
      startSubs('all')
    },
    startAllSubs(){
      if (webSocket && webSocket.readyState != webSocket.OPEN) {
        serverTime = null
        clearInterval(timer)
        timer = null
        webSocket = createWebSocket('all')
      }
    },
    checkNetWork(callback){
      checkNetWorkCallback = callback
    },
    getRate(callback){
      rateCallback = callback
    },
    subscribe,
    unsubscribe
  }
}
